secure-agent-setup: layered credential isolation + 7-day pinned tools#11
Merged
Conversation
Adds the framework's recommended secure-agent setup — a layered
defence for running Claude Code (or any other SKILL.md-aware
agent) against pre-disclosure CVE content without unfettered
access to host credentials. The framework dogfoods the
configuration via `.claude/settings.json`; adopters scaffold their
own copy from the example block in the new doc.
## Layered defence
The new setup is four layers, each implemented in this commit:
Layer 0 — clean env claude-iso.sh wrapper
Layer 1 — fs sandbox .claude/settings.json sandbox.*
Layer 2 — tool perms .claude/settings.json permissions.deny
Layer 3 — confirm-on-write .claude/settings.json permissions.ask
Layers 1-3 share `.claude/settings.json`. Layer 0 is a separate
shell wrapper that strips credential-shaped env vars from the
parent shell before exec-ing claude.
## 7-day cooldown for system-tool versions
Mirrors the framework's existing 7-day cooldown convention
(`[tool.uv] exclude-newer = "7 days"` in pyproject.toml; weekly
Dependabot updates with 7-day cooldown in dependabot.yml). Every
host-system tool the secure setup depends on (bubblewrap, socat,
claude-code) is pinned in `tools/agent-isolation/pinned-versions.toml`
to a version that was released at least 7 days before the manifest
was last touched (`pinned_at`).
A side-effect-free check script
(`tools/agent-isolation/check-tool-updates.sh`) compares the pinned
versions to upstream and prints upgrade candidates that have
themselves aged past the 7-day cutoff. The script never installs,
never edits the manifest, never opens a PR — bumps require explicit
maintainer review per the procedure documented in
`secure-agent-setup.md`.
The doc also walks through wiring the script into a weekly
`/schedule` routine so upgrade candidates surface automatically
without manual prompting; the scheduled agent has no special
permission to install — the surfaced candidate is a proposal, not
an action.
## Files
| File | Purpose |
|---|---|
| `secure-agent-setup.md` | User-facing doc. Threat model, layered defence walkthrough, install commands per distro, bump procedure, adopter scaffold, verification commands, residual risks. |
| `.claude/settings.json` | The framework's own dogfooded secure config — sandbox + permissions for cwd-rooted Claude Code sessions in this repo. |
| `tools/agent-isolation/pinned-versions.toml` | Machine-readable manifest of pinned upstream versions for `bubblewrap`, `socat`, `claude-code`. Each entry carries a `released` date that satisfies the 7-day cooldown. |
| `tools/agent-isolation/check-tool-updates.sh` | Reads the manifest and reports upstream releases newer than the pin AND aged past 7 days. Side-effect-free. |
| `tools/agent-isolation/claude-iso.sh` | Layer-0 shell wrapper — `env -i` + tiny passthrough list. |
| `tools/agent-isolation/README.md` | Files-and-usage overview for the new directory. |
`README.md` and `AGENTS.md` updates: link to the new doc from the
"agent prerequisites" section and from "Local setup".
## Pinned versions (at time of writing, all aged past 7 days)
bubblewrap 0.11.1 released 2026-03-21
socat 1.8.1.1 released 2026-03-13
claude-code 2.1.117 released 2026-04-22
The check script verified these by querying upstream:
$ bash tools/agent-isolation/check-tool-updates.sh
TOOL PINNED PINNED@ UPSTREAM UPSTREAM@ STATUS
bubblewrap 0.11.1 2026-03-21 0.11.1 2026-03-21 ✓ up to date
socat 1.8.1.1 2026-03-13 1.8.1.1 2026-02-12 ✓ up to date
claude-code 2.1.117 2026-04-22 2.1.117 2026-04-22 ✓ up to date
Latest claude-code (v2.1.123, released 2026-04-29) is intentionally
NOT picked up — within the 7-day cooldown.
## Test plan
- ✅ `prek run --all-files` passes (doctoc generated TOCs for the
two new .md files; all other hooks clean).
- ✅ The check script runs end-to-end, queries upstream, prints the
expected status table.
- ✅ The example `.claude/settings.json` parses as valid JSON
(`python3 -c 'import json; json.load(open(".claude/settings.json"))'`).
- The actual filesystem-sandbox enforcement requires bubblewrap on
the host — the framework maintainer's first invocation of
Claude Code with this settings.json after merge will exercise it
end-to-end.
Generated-by: Claude Code (Claude Opus 4.7)
Member
|
cool! big fan of bubblewrap. it remains a bit odd to have claude take care of wrapping instead of wrapping claude, but 🤷 😄 |
Member
Author
|
Yeah ... and I have some follow-up after testing (including my mint distro quirks and setting up my Yubikey) |
6 tasks
5 tasks
potiuk
added a commit
that referenced
this pull request
May 30, 2026
Fifth and final PR of the security genericization series. Lifts the remaining 4 docs in docs/security/ to read config knobs from projects/_template/project.md and the contract docs from PR1-PR4 (cve_authority.*, governance.*, security_inbox.*, forwarders.*, archive_system.*, scope_detection.*). Plus a final scrub of 4 skills for leftover ASF/Vulnogram literals. Byte-equivalent for the airflow-s adopter: every ASF/Airflow/ Vulnogram-specific value either resolves through a config knob whose ASF default matches today's behaviour, OR stays as one named-example aside in generic prose. Per-target lifts: - docs/security/threat-model.md (+107/-77) — Purpose/Scope/ Assumptions reframed from "ASF"/"PMC" to governance-knob terms. STRIDE matrix rows A.6/A.7/C.1-C.4/E.1-E.2 lifted: Vulnogram -> <cve-tool>; security@apache.org -> <security-list>; DRAFT/REVIEW/READY/PUBLIC -> cve_authority.states sequence (allocated -> review-ready -> publish-ready -> public). Mitigations M.10/M.16/M.18/M.19/M.27 + residual risks #3/#8/#10/#11 + re-audit cadence ownership generalised. - docs/security/forwarder-routing-policy.md (+42/-27) — references the optional security-issue-import-via-forwarder sub-skill from PR3 (#387) and the tools/forwarder-relay/README.md contract. Replaces "ASF-security relay" / "security@apache.org" with forwarders.enabled / <security-list> / foundation_security_address. ASF-Airflow shown as a named-example aside per concept. - docs/security/how-to-fix-a-security-issue.md (+20/-8) — "governance-authorised member of the adopting project (per governance.cve_allocation_gate)" replaces "PMC member of apache/airflow"; <cve-tool> + cve_authority.* replaces Vulnogram- specific URLs and state names; archive_system.advisory_publication_signal_url replaces the lists.apache.org users-list URL. - docs/security/new-members-onboarding.md (+26/-13) — onboarding- style register preserved. "PMC members and committers" reframed as "governance body that satisfies governance.cve_allocation_gate"; per-user-config "PMC status" steps reference the governance knob; Vulnogram steps reference <cve-tool> via cve_authority.record_url_template. - Final scrub of 4 skills (+17/-15 net): security-issue-import, security-issue-import-via-forwarder, security-issue-invalidate, security-issue-fix — leftover literal references caught and lifted to roster.bare_name_handles / governance.escalation_contact / forwarders.<adapter>.contact_handle. Aggregate: 8 files, +240/-156 lines. That closes the series. Five PRs (#381, #386, #387, #388, this) transitioned the security skill family from Airflow/ASF-coupled to a generic framework with ASF as the default-configured option. The airflow-s adopter, with the ASF defaults baked into project.md, sees byte-equivalent behaviour throughout. Non-ASF adopters override specific dimensions (CVE authority, mail provider, archive system, governance gate, scope axis) by changing only their <project-config>/ files. Generated-by: Claude Code (Opus 4.7)
potiuk
pushed a commit
that referenced
this pull request
Jun 30, 2026
…ls (#651) * feat(validator): add adapter authoring smoke check for contract:* tools Add a SOFT advisory check (aspect #11) to skill-and-tool-validator that verifies every contract:* adapter tool README declares the three authoring fields the adapter contract requires: credential/privacy handling, supported operations, and adopter config keys. All three checks are SOFT so legacy adapters can be brought into compliance deliberately without blocking unrelated changes. Twelve advisories fire on the current tree; exit code stays 0. New TestValidateAdapterAuthoring class adds 13 targeted tests. Generated-by: Claude (Opus 4.7) * fix two false positives and add to implmentation plan
potiuk
pushed a commit
to justinmclean/airflow-steward
that referenced
this pull request
Jun 30, 2026
Add validate_modes_doc_consistency (SOFT, category modes-doc-consistency) to the skill-and-tool-validator. The check compares docs/modes.md against live skills/*/SKILL.md frontmatter across four dimensions: 1. Listed skill missing from disk — row exists in modes.md but skills/<slug>/ does not. 2. Mode mismatch — a skill's mode: frontmatter differs from the section it appears in (e.g. listed under Triage but mode: Mentoring). 3. Skill count mismatch — the integer in "Modes at a glance" Skill count column does not equal the actual row count in that mode's section. 4. Unlisted skill — a live skill has a valid mode: frontmatter value but is absent from the corresponding docs/modes.md section. On the live tree the check surfaces two real gaps: - reviewer-routing has mode: Triage but is absent from docs/modes.md - good-first-issue-sweep has mode: Mentoring but is absent from docs/modes.md Ships 19 tests in TestParseModesDocs + TestValidateModeDocConsistency; all 283 validator tests pass. Generated-by: Claude (Opus 4.7)
potiuk
pushed a commit
that referenced
this pull request
Jun 30, 2026
Add validate_modes_doc_consistency (SOFT, category modes-doc-consistency) to the skill-and-tool-validator. The check compares docs/modes.md against live skills/*/SKILL.md frontmatter across four dimensions: 1. Listed skill missing from disk — row exists in modes.md but skills/<slug>/ does not. 2. Mode mismatch — a skill's mode: frontmatter differs from the section it appears in (e.g. listed under Triage but mode: Mentoring). 3. Skill count mismatch — the integer in "Modes at a glance" Skill count column does not equal the actual row count in that mode's section. 4. Unlisted skill — a live skill has a valid mode: frontmatter value but is absent from the corresponding docs/modes.md section. On the live tree the check surfaces two real gaps: - reviewer-routing has mode: Triage but is absent from docs/modes.md - good-first-issue-sweep has mode: Mentoring but is absent from docs/modes.md Ships 19 tests in TestParseModesDocs + TestValidateModeDocConsistency; all 283 validator tests pass. Generated-by: Claude (Opus 4.7)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the framework's recommended secure agent setup — a layered defence for running Claude Code (or any other
SKILL.md-aware agent) against pre-disclosure CVE content without unfettered host-credential access. The framework dogfoods the config in.claude/settings.json; adopters scaffold their own copy from the example block in the new doc.The setup is four layers, each implemented in this PR:
tools/agent-isolation/claude-iso.sh—env -i+ tiny passthrough list.claude/settings.jsonsandbox.enabled: true+ bubblewrap (Linux) / Seatbelt (macOS).claude/settings.jsonpermissions.denyfor Read / Edit / Write / Bash.claude/settings.jsonpermissions.askforgit push,gh pr create, etc.7-day cooldown for system-tool versions
Mirrors the framework's existing 7-day cooldown convention (
[tool.uv] exclude-newer = "7 days"inpyproject.toml; weekly Dependabot with 7-day cooldown independabot.yml). Every host-system tool the secure setup depends on is pinned intools/agent-isolation/pinned-versions.tomlto a version released at least 7 days before the manifest was last touched.bubblewrapsocatclaude-codeA side-effect-free check script (
check-tool-updates.sh) compares pinned versions to upstream and prints upgrade candidates that have themselves aged past 7 days. No auto-install, no auto-edit of the manifest, no auto-PR — bumps require explicit maintainer review per the procedure insecure-agent-setup.md. The doc also walks through wiring the script into a weekly/scheduleroutine for ongoing visibility.Files added
secure-agent-setup.md.claude/settings.jsontools/agent-isolation/pinned-versions.tomlreleaseddates that satisfy the 7-day cooldown.tools/agent-isolation/check-tool-updates.shtools/agent-isolation/claude-iso.shtools/agent-isolation/README.mdFiles updated
README.mdandAGENTS.mdlink to the new doc from the agent-prerequisites and Local-setup sections.Test plan
prek run --all-filespasses (doctoc generated TOCs for the two new .md files; all other hooks clean)..claude/settings.jsonparses as valid JSON (python3 -c 'import json; json.load(open(".claude/settings.json"))').Out of scope
sandbox/permissions).🤖 Generated with Claude Code